#!/bin/bash

umask 0022

set +o posix

current_dir=$(cd $(dirname $0) && command pwd -P)
bootstrapper=$current_dir/script/bootstrapper.conf
source $current_dir/script/comm.sh
source $current_dir/script/render.sh
source $current_dir/script/install/compiler.sh
source $current_dir/script/install/bisheng.sh
source $current_dir/script/install/gcc.sh
source $current_dir/script/install/hio.sh
source $current_dir/script/logger.sh
source $current_dir/script/check_dep.sh

read_value()
{
    local file="$1"
    local variable_name="$2"
    local value=$(grep "$variable_name" "$file" | awk -F= '{print $2}')
    echo "$value"
}
software_version=$(read_value "$bootstrapper" "software_version")
software_name=$(read_value "$bootstrapper" "software_name")
software_size=$(read_value "$bootstrapper" "software_size")
KML_tar_name=$(read_value "$bootstrapper" "KML_TAR")
Bisheng_tar_name=$(read_value "$bootstrapper" "Bisheng_tar")
Gcc_tar_name=$(read_value "$bootstrapper" "Gcc_tar")
HIO_tar=$(read_value "$bootstrapper" "HIO_tar")

HMPI_tar=$(read_value "$bootstrapper" "HMPI_tar") # Hyper-MPI_x.x.x_aarch64
HMPI_Bisheng_version=$(read_value "$bootstrapper" "HMPI_Bisheng_version") # Bisheng
HMPI_Gcc_version=$(read_value "$bootstrapper" "HMPI_Gcc_version") # GCC
HMPI_KylinSec_version=$(read_value "$bootstrapper" "HMPI_KylinSec_version") # KylinSec
HMPI_KylinSec_suffix=$(read_value "$bootstrapper" "HMPI_KylinSec_suffix") # MLNX-OFED5.8
HMPI_KylinV10HPC_version=$(read_value "$bootstrapper" "HMPI_KylinV10HPC_version") # KylinV10-HPC
HMPI_KylinV10HPC_suffix=$(read_value "$bootstrapper" "HMPI_KylinV10HPC_suffix") # MLNX-OFED5.8
HMPI_KylinV10Industry_version=$(read_value "$bootstrapper" "HMPI_KylinV10HPC_version") # KylinV10-HPC
HMPI_KylinV10Industry_suffix=$(read_value "$bootstrapper" "HMPI_KylinV10HPC_suffix") # MLNX-OFED5.8
HMPI_KylinV10SP2_version=$(read_value "$bootstrapper" "HMPI_KylinV10SP2_version") # KylinV10SP2
HMPI_KylinV10SP2_suffix=$(read_value "$bootstrapper" "HMPI_KylinV10SP2_suffix") # MLNX-OFED5.4
HMPI_KylinV10BETAHPC_version=$(read_value "$bootstrapper" "HMPI_openEulerSP4_version") # openEuler22.03SP4
HMPI_KylinV10BETAHPC_suffix=$(read_value "$bootstrapper" "HMPI_openEulerSP4_suffix") # MLNX-OFED5.8
HMPI_openEuler20SP3_version=$(read_value "$bootstrapper" "HMPI_openEuler20SP3_version") # openEuler20.03
HMPI_openEuler20SP3_suffix=$(read_value "$bootstrapper" "HMPI_openEuler20SP3_suffix") # MLNX-OFED5.8
HMPI_openEulerSP2_version=$(read_value "$bootstrapper" "HMPI_openEulerSP2_version") # openEuler22.03
HMPI_openEulerSP2_suffix=$(read_value "$bootstrapper" "HMPI_openEulerSP2_suffix") # MLNX-OFED5.8
HMPI_openEulerSP4_version=$(read_value "$bootstrapper" "HMPI_openEulerSP4_version") # openEuler22.03SP4
HMPI_openEulerSP4_suffix=$(read_value "$bootstrapper" "HMPI_openEulerSP4_suffix") # MLNX-OFED5.8
HMPI_suffix_default=$(read_value "$bootstrapper" "HMPI_suffix_default") # rdma-core

# check the integrity of your component installation
comp_intg_check() {
    local path=$1
    if [ -e $path/.install ]; then
        return 0
    else
        return 1
    fi
}

# add integrity file to component
comp_intg_add() {
    local path=$1
    if [ -e $path ]; then
        touch $path/.install
    else
        logError "$path not exist"
    fi
}

comp_cleanup() {
    local path=$1
    if [ ! -e $path ]; then
        return
    fi
    if ! comp_intg_check $path; then
        rm -rf $path
        logError "clean up $path"
    fi
}

install_kml() {
    local compiler=$1
    local kml_tar_path=$current_dir/package/$KML_tar_name.tar.gz
    local kml_root=$software_install_path/kml
    mkdir -p $kml_root
    local full_lapack_option=""
    local full_scalapack_option=""
    local bisheng=""
    local gcc=""
    trap_add "comp_cleanup '${kml_root}/${compiler}'" EXIT
    if comp_intg_check "${kml_root}/${compiler}"; then
        logSuccess "-- KML Already Install"
        return
    fi
    local compiler_opt="--use-${compiler}"
    tar -xzf $kml_tar_path -C $current_dir/package/ --no-same-owner --same-permissions
    $current_dir/package/$KML_tar_name/install.sh --prefix=$kml_root $compiler_opt
    if [ $? -eq 0 ]; then
        comp_intg_add "${kml_root}/${compiler}"
        logSuccess "KML Installation Finished"
    else
        logError "KML Installation Failed"
    fi
}

KML_install() {
    local compiler=$1
    logInfo "Start Installing $1 compiled KML"
    check_dep "$current_dir/script/kml_requirement.conf"
    install_kml $compiler
}

install_kupl() {
    local compiler=$1
    local comp_root=$software_install_path/kupl
    mkdir -p $comp_root/$compiler
    trap_add "comp_cleanup '${comp_root}/${compiler}'" EXIT
    if comp_intg_check "${comp_root}/${compiler}"; then
        logSuccess "-- KUPL Already Install"
        return
    fi
    local comp_pkg_path=$(find $current_dir/package -maxdepth 1 -iname "KUPL*${compiler}*.tar.gz" -type f)
    tar xf $comp_pkg_path -C $comp_root/$compiler --strip-components=1 --no-same-owner --same-permissions
    if [ $? -eq 0 ]; then
        comp_intg_add "$comp_root/$compiler"
        logSuccess "KUPL Installation Finished."
    else
        logError "KUPL Installation Failed."
    fi
}

KUPL_install() {
    local compiler=$1
    logInfo "Start Installing $1 compiled KUPL"
    install_kupl $compiler
}

install_kulitho() {
    local compiler=$1
    local comp_root=$software_install_path/kulitho
    mkdir -p $comp_root/$compiler
    trap_add "comp_cleanup '${comp_root}/${compiler}'" EXIT
    if comp_intg_check "${comp_root}/${compiler}"; then
        logSuccess "-- KULITHO Already Install"
        return
    fi

    local default_package_path="$current_dir/package"
    local package_path
    local comp_pkg_path
    if [ $one_click -eq 1 ]; then
        package_path=$(readlink -f "${kulitho_package_path:-$default_package_path}")
        comp_pkg_path=$(find $package_path -maxdepth 1 -iname "KuLitho*${compiler}*.tar.gz" -type f)
        if [[ "$comp_pkg_path" == "" ]]; then
            logError "cannot found KuLitho $compiler install package in $package_path, KULITHO Installation Failed."
            return
        fi
    else
        read -e -p "Enter the KuLitho install package path (default: $default_package_path): " kulitho_package_path
        package_path=$(readlink -f "${kulitho_package_path:-$default_package_path}")
        comp_pkg_path=$(find $package_path -maxdepth 1 -iname "KuLitho*${compiler}*.tar.gz" -type f)
        while [[ "$comp_pkg_path" == "" ]]; do
            read -e -p "cannot found KuLitho $compiler install package in $package_path, continue installing KuLitho? (y/n): " reinstall
            if [[ "$reinstall" == "n" ]]; then
                logError "KULITHO Installation Failed."
                return
            else
                read -e -p "Enter the KuLitho install package path (default: $default_package_path): " kulitho_package_path
                package_path=$(readlink -f "${kulitho_package_path:-$default_package_path}")
                comp_pkg_path=$(find $package_path -maxdepth 1 -iname "KuLitho*${compiler}*.tar.gz" -type f)
                continue;
            fi
        done
    fi

    tar xf $comp_pkg_path -C $comp_root/$compiler --strip-components=1 --no-same-owner --same-permissions
    if [ $? -eq 0 ]; then
        comp_intg_add "$comp_root/$compiler"
        logSuccess "KULITHO Installation Finished."
    else
        logError "KULITHO Installation Failed."
    fi
}

KULITHO_install() {
    local compiler=$1
    logInfo "Start Installing $1 compiled KULITHO"
    install_kulitho $compiler
}

install_kutacc() {
    local compiler=$1
    local comp_root=$software_install_path/kutacc
    mkdir -p $comp_root/$compiler
    trap_add "comp_cleanup '${comp_root}/${compiler}'" EXIT
    if comp_intg_check "${comp_root}/${compiler}"; then
        logSuccess "-- KuTACC Already Install"
        return
    fi
    local comp_pkg_path=$(find $current_dir/package -maxdepth 1 -iname "KuTACC*${compiler}*.tar.gz" -type f)
    tar xf $comp_pkg_path -C $comp_root/$compiler --strip-components=1 --no-same-owner --same-permissions
    if [ $? -eq 0 ]; then
        comp_intg_add "$comp_root/$compiler"
        logSuccess "KuTACC Installation Finished."
    else
        logError "KuTACC Installation Failed."
    fi
}

KuTACC_install() {
    local compiler=$1
    logInfo "Start Installing $1 compiled KuTACC"
    install_kutacc $compiler
}

untar_HMPI()
{
    local pretty_os_name=$(get_pretty_os_name)
    if [[ ${pretty_os_name} =~ "KylinLinuxAdvancedServerV10(Jasmine)" ]]; then
        hmpi_os_name=${HMPI_KylinV10BETAHPC_version}
        hmpi_suffix=${HMPI_KylinV10BETAHPC_suffix}
    elif [[ ${pretty_os_name} =~ "KylinLinuxAdvancedServerIndustryV10" ]]; then
        hmpi_os_name=${HMPI_KylinV10Industry_version}
        hmpi_suffix=${HMPI_KylinV10Industry_suffix}
    # KylinSec
    elif [[ ${pretty_os_name} =~ "KylinSecOSLinux3(Qomolangma)" ]]; then
        hmpi_os_name=${HMPI_KylinSec_version}
        hmpi_suffix=${HMPI_KylinSec_suffix}
    # KylinV10-HPC
    elif [[ ${pretty_os_name} =~ "KylinLinuxAdvancedServerV10(Hydrogen)" ]]; then
        hmpi_os_name=${HMPI_KylinV10HPC_version}
        hmpi_suffix=${HMPI_KylinV10HPC_suffix}
    # KylinV10-SP2
    elif [[ ${pretty_os_name} =~ "KylinLinuxAdvancedServerV10(Sword)" ]]; then
        hmpi_os_name=${HMPI_KylinV10SP2_version}
        hmpi_suffix=${HMPI_KylinV10SP2_suffix}
    # openEuler22.03
    elif [[ ${pretty_os_name} =~ openEuler22.03\(LTS-SP[1-4]\) || ${pretty_os_name} =~ openEuler22.03\(LTS\) ]]; then
        hmpi_os_name=${HMPI_openEulerSP2_version}
        hmpi_suffix=${HMPI_openEulerSP2_suffix}
        if [[ ${pretty_os_name} =~ "openEuler22.03(LTS-SP4)" ]]; then
            hmpi_os_name=${HMPI_openEulerSP4_version}
            hmpi_suffix=${HMPI_openEulerSP4_suffix}
        fi
    # openEuler20.03
    elif [[ ${pretty_os_name} =~ openEuler20.03\(LTS-SP[1-4]\) || ${pretty_os_name} =~ openEuler20.03\(LTS\) ]]; then
        hmpi_os_name=${HMPI_openEuler20SP3_version}
        hmpi_suffix=${HMPI_openEuler20SP3_suffix}
    else
        logError "Unsupported os $pretty_os_name, please check support list."
        hmpi_is_support=false
        return
    fi

    local net_type
    local hmpi_flag=1
    if [[ ${one_click} -eq 0 ]]; then
        while [[ ${hmpi_flag} -eq 1 ]]; do
            echo "Please enter the type of HMPI: 'rdma'(default) or 'mlnx'."
            read net_type
            if [[ "$net_type" != "rdma" && "$net_type" != "mlnx" && "$net_type" != "" ]]; then
                logError "'$net_type' has an invalid value."
                continue
            else
                if [[ "$net_type" == "" ]]; then
                    hmpi_type="rdma"
                else
                    hmpi_type=${net_type}
                fi
                hmpi_flag=0
            fi
        done
    fi
    if [[ "$hmpi_type" == "rdma" ]]; then
        if [[ ${pretty_os_name} =~ "KylinLinuxAdvancedServerV10(Sword)" ]]; then
            logWarn "Current system does not support RDMA-type HMPI. Installing Mellanox-type HMPI for you."
            hmpi_suffix=${HMPI_KylinV10SP2_suffix}
        elif [[ ${pretty_os_name} =~ openEuler20.03\(LTS-SP[1-4]\) || ${pretty_os_name} =~ openEuler20.03\(LTS\) ]]; then
            logWarn "Current system does not support RDMA-type HMPI. Installing Mellanox-type HMPI for you."
            hmpi_suffix=${HMPI_openEuler20SP3_suffix}
        else
            hmpi_suffix=${HMPI_suffix_default}
        fi
    fi

    local compiler=$1
    if [ ${compiler} == "gcc" ]; then
        local compiler_version=$HMPI_Gcc_version
    elif [ ${compiler} == "bisheng" ]; then
        local compiler_version=$HMPI_Bisheng_version
    fi
    local compiler_path="${compiler}"
    local hmpi_tar_name=$(ls -l ${current_dir}/package | awk '{print $NF}' | grep "^Hyper-MPI" | grep "release" | grep "${hmpi_os_name}_${compiler_version}_${hmpi_suffix}")
    hmpi_tar_name=${hmpi_tar_name%.tar.gz}
    local hmpi_tar_path=$current_dir/package/$hmpi_tar_name.tar.gz
    local hmpi_path=$software_install_path/hmpi/$compiler_path
    if [ ! -e $hmpi_path ]; then
        mkdir -p $hmpi_path
    fi
    if [ ! -e $hmpi_tar_path ]; then
        logError "HMPI Release Version Installation File Miss, Please Manually Install."
    else
        tar -xf $hmpi_tar_path -C $hmpi_path --strip-components=1 --no-same-owner --same-permissions
        if [ $? -eq 0 ]; then
            logSuccess "HMPI Release Version Installation Finished."
        else
            logError "HMPI Release Version Installation Failed."
        fi
    fi

    local hmpi_tar_name=$(ls -l ${current_dir}/package | awk '{print $NF}' | grep "^Hyper-MPI" | grep "debug" | grep "${hmpi_os_name}_${compiler_version}_${hmpi_suffix}")
    hmpi_tar_name=${hmpi_tar_name%.tar.gz}
    hmpi_tar_path=$current_dir/package/$hmpi_tar_name.tar.gz
    hmpi_path=$software_install_path/hmpi/$compiler_path
    if [ ! -e $hmpi_path ]; then
        mkdir -p $hmpi_path
    fi
    if [ ! -e $hmpi_tar_path ]; then
        logError "HMPI Debug Version Installation File Miss, Please Manually Install."
    else
        tar -xf $hmpi_tar_path -C $hmpi_path --strip-components=1 --no-same-owner --same-permissions
        if [ $? -eq 0 ]; then
            logSuccess "HMPI Debug Version Installation Finished."
        else
            logError "HMPI Debug Version Installation Failed."
        fi
    fi
}

install_hio() {
    local hio_tar_path=$current_dir/package/$HIO_tar.tar.gz
    local hio_root=$software_install_path/hio
    mkdir -p $hio_root
    trap_add "comp_cleanup '${hio_root}'" EXIT
    if comp_intg_check "${hio_root}"; then
        logSuccess "-- HIO Already Install"
        return
    fi
    local comp_pkg_path=$(find $current_dir/package -maxdepth 1 -iname "IO_Middleware*.tar.gz" -type f)
    tar xf $comp_pkg_path -C $hio_root --strip-components=1 --no-same-owner --same-permissions
    if [ $? -eq 0 ]; then
        comp_intg_add "${hio_root}"
        logSuccess "HIO Installation Finished"
    else
        logError "HIO Installation Failed"
    fi
}

HIO_install() {
    logInfo "Start Installing HIO"
    check_dep "$current_dir/script/hio_requirement.conf"
    install_hio
}

hmpi_is_support=true
HMPI_install() {
    local compiler=$1
    logInfo "Start Installing $1 compiled Hyper MPI"
    check_dep "$current_dir/script/hmpi_requirement.conf"
    local hmpi_root=$software_install_path/hmpi
    local bisheng=""
    local gcc=""
    trap_add "comp_cleanup '${hmpi_root}/${compiler}'" EXIT
    if ! comp_intg_check "$hmpi_root/${compiler}"; then
        untar_HMPI ${compiler}
        if [ "$hmpi_is_support" = true ]; then
            comp_intg_add "$hmpi_root/${compiler}"
        fi
    else
        logSuccess "-- Hyper MPI Already Install"
    fi
}

Bisheng_Compiler_install() {
    logInfo "Start Installing Bisheng Compiler"
    local compiler_path=$software_install_path/compiler
    local bisheng_path=$compiler_path/bisheng
    local Bisheng_tar_path=$current_dir/package/$Bisheng_tar_name.tar.gz
    trap_add "comp_cleanup '${bisheng_path}'" EXIT
    if [ ! -e $bisheng_path ]; then
        mkdir -p $bisheng_path
    fi
    if [ ! -e $Bisheng_tar_path ]; then
        logError "Bisheng Compiler Installation File Miss, Please Manually Install."
    else
        if ! comp_intg_check "$bisheng_path"; then
            tar -xf $Bisheng_tar_path -C $bisheng_path --strip-components=1 --no-same-owner --same-permissions
            if [ $? -eq 0 ]; then
                logSuccess "Bisheng Compiler Installation Finished."
                comp_intg_add "$bisheng_path"
            else
                logError "Bisheng Compiler Installation Failed."
            fi
        else
            logSuccess "-- Bisheng Compiler Already Install"
        fi
    fi
}

GCC_Compiler_install() {
    logInfo "Start Installing Gcc For openEuler"
    local compiler_path=$software_install_path/compiler
    local gcc_path=$compiler_path/gcc
    local Gcc_tar_path=$current_dir/package/$Gcc_tar_name.tar.gz
    trap_add "comp_cleanup '${gcc_path}'" EXIT
    if [ ! -e $gcc_path ]; then
        mkdir -p $gcc_path
    fi
    if [ ! -e $Gcc_tar_path ]; then
        logError "Gcc For openEuler Installation File Miss, Please Manually Install."
    else
        if ! comp_intg_check "$gcc_path"; then
            tar -xf $Gcc_tar_path -C $gcc_path --strip-components=1 --no-same-owner --same-permissions
            if [ $? -eq 0 ]; then
                logSuccess "Gcc For openEuler Installation Finished."
                comp_intg_add "$gcc_path"
            else
                logError "Gcc For openEuler Installation Failed."
            fi
        else
            logSuccess "-- Gcc For openEuler Already Install"
        fi
    fi
}

install_dir_space_check()
{
    local install_dir=$1
    local avail_size=$(df -k ${install_dir} | sed -n '2p' | awk -F " " '{print $(NF-2)}')
    if [ $software_size -gt $avail_size ]; then
        logFail "The space of the HPCKit installation directory is insufficient."
        logWarn "About 10 GB space is required for installing HPCKit."
        logWarn "Run the 'df -h ${install_dir}' command to check the space of the installation directory."
        exit 1
    fi
}

selected_install_path=""
software_install_path=""
install_history_file_path="$HOME/.HPCKit/install_history"
install_history_file="$install_history_file_path/$software_version"
same_install_path=false
select_install_path() {
    local default_install_path="/opt"
    if [ ! -w "$default_install_path" ]; then
        default_install_path=~
    fi
    local while_flag=1
    while [[ ${while_flag} -eq 1 ]]; do
        if [[ ${one_click} -eq 0 ]]; then
            read -e -p "Enter the installation path (default: $default_install_path): " custom_path

            selected_install_path=$(readlink -f "${custom_path:-$default_install_path}")

            # check install history
            if [ -e "$install_history_file" ]; then
                local install_history=()
                while IFS= read -r line; do
                    install_history+=("${line#*:}")
                done < "$install_history_file"

                if [ "${#install_history[@]}" -gt 0 ]; then
                    for path in "${install_history[@]}"; do
                        if [ "$selected_install_path" == "$path" ]; then
                            same_install_path=true
                            break
                        fi
                    done
                    local already_installed="${install_history[0]}"
                    for ((i = 1; i < ${#install_history[@]}; i++)); do
                        already_installed="$already_installed and ${install_history[i]}"
                    done
                    logWarn "HPCKit $software_version already installed in $already_installed."
                    prompt_for_yes_no "Do you still want to install in $selected_install_path? (y/n): "
                    if [ $? -eq 1 ]; then
                        exit
                    fi
                fi
            fi
        else
            while_flag=0
            selected_install_path=$(readlink -f "${selected_install_path}")
        fi

        if [ ! -e "$selected_install_path" ]; then
            prompt_for_yes_no "The specified path does not exist. Do you want to create it? (y/n): "
            if [ $? -eq 1 ]; then
                continue
            fi
        fi

        # $selected_install_path might be a file
        local errMsg=$(mkdir -p "$selected_install_path" 2>&1)
        if [ "$errMsg" != "" ]; then
            logError "$errMsg, Please choose another path."
            if [[ ${one_click} -eq 1 ]]; then
                exit 1
            else
                continue
            fi
        fi

        if [ ! -w "$selected_install_path" ]; then
            logError "Error: You do not have permission to write to ${selected_install_path}. Please choose another path."
            if [[ ${one_click} -eq 1 ]]; then
                exit 1
            else
                continue
            fi
        fi

        break
    done

    # remove last /
    selected_install_path=${selected_install_path%*/}

    install_dir_space_check ${selected_install_path}

    logSuccess "You have selected: $selected_install_path"
}
finish_installation()
{
    local file_setvars="$current_dir/script/setvars.sh"
    local file_uninstall="$current_dir/script/uninstall.sh"
    local file_modulefilesetup="$current_dir/script/modulefiles-setup.sh"
    cp $file_setvars $software_install_path
    cp $file_uninstall $software_install_path
    cp $file_modulefilesetup $software_install_path
    local setup="$software_install_path/modulefiles-setup.sh"
    if [[ -e $setup ]]; then
        sh $setup
    fi
    if [ "$same_install_path" == false ]; then
        echo "install_root:$selected_install_path" >> $install_history_file
    fi
    find $selected_install_path/$software_name/$software_version -type d -exec chmod 755 {} \;
}

make_install_path()
{
    local path="$selected_install_path/$software_name/$software_version"
    local errMsg=$(mkdir -p "$path" 2>&1)
    if [ "$errMsg" != "" ]; then
        logError "$errMsg"
        exit
    fi
    software_install_path="$path"
}

check_latest()
{
    local base_dir="$selected_install_path/$software_name"
    # get all subdirectories
    local subdirectories=($(find "$base_dir" -maxdepth 1 -mindepth 1 -type d))

    # Filter out subdirectories with similar date formats
    local filtered_directories=()
    for dir in "${subdirectories[@]}"; do
        local dir_name=$(basename "$dir")
        if [[ "$dir_name" =~ ^[0-9]{2}\.[0-9]{1,2}\.[0-9A-Za-z]{1,3}$ ]]; then
            filtered_directories+=("$dir")
        fi
    done

    # Find the subdirectory with the closest date
    local latest_directory=""
    local latest_date="00000000"
    for dir in "${filtered_directories[@]}"; do
        local dir_name=$(basename "$dir")

        local year=$(echo "$dir_name" | awk -F'.' '{print $1}')
        local month=$(echo "$dir_name" | awk -F'.' '{print $2}')
        local day_part=$(echo "$dir_name" | awk -F'.' '{print $3}')
        local day=$(echo "$day_part" | sed 's/[^0-9]//g')
        local version_part=$(echo "$day_part" | sed 's/[0-9]//g')
        if [ -z "$version_part" ]; then
            day=$(printf "%02d" 99)
        fi

        # date format YYYYMMDD
        local current_date=$(printf "%04d%02d%02d" "$year" "$month" "$day")

        if [ "$current_date" -gt "$latest_date" ]; then
            latest_date="$current_date"
            latest_directory="$dir"
            latest_dir_name="$dir_name"
        elif [ "$current_date" -eq "$latest_date" ]; then
            # If dates are equal, compare the directory names lexicographically
            if [[ "$dir_name" > "$latest_dir_name" ]]; then
                latest_directory="$dir"
                latest_dir_name="$dir_name"
            fi
        fi
    done

    # create symbolic link latest
    if [ -n "$latest_directory" ]; then
        local soft_dir=$(basename "$latest_directory")
        ln -sfn "$soft_dir" "$base_dir/latest"
    fi
}

trace_install() {
    local files=$(find $software_install_path -not -type d)
    local dirs=$(find $software_install_path -maxdepth 1 -type d)
    echo "$files"
    echo "$dirs"
}

gen_trace_file() {
    local before_install="$1"
    local after_install="$(trace_install)"
    local new_files=`grep -xvFf  <( echo "$before_install" ) <( echo "$after_install" ) | awk -v root="$software_install_path" '{print substr($0, length(root)+2)}'`
    local trace_file="$software_install_path/.INSTALL_TRACE"
    touch "$trace_file"
    # chattr -i "$trace_file"
    if [ "$new_files" != "" ]; then
        echo "$new_files" >> "$trace_file"
        # TODO Remove Duplicates
    fi
    sort -r -o $trace_file $trace_file
    # chattr +i "$trace_file"
}

check_os() {
    local pretty_os_name=$(get_pretty_os_name)
    local support_os=$(read_value "$bootstrapper" "SUPPORT_OS_NAME")
    IFS=';' read -r -a os_list <<< "$support_os"
    # 检查 pretty_os_name 是否在 os_list 中
    local found=false
    for os in "${os_list[@]}"; do
        if [[ "$os" =~ "$pretty_os_name" ]]; then
            found=true
            break
        fi
    done

    if [ "$found" = false ]; then
        logError "$pretty_os_name is not in the list of supported OS."
        exit 1
    fi
}

install_selected_software() {
    check_os
    create_log_file
    mkdir -p $install_history_file_path
    clear_screen

    logInfo "Start installing HPCKit..."
    select_install_path
    make_install_path
    check_latest

    user_choose "install_compiler"
    local before_install=$(trace_install)
    trap_add "gen_trace_file '$before_install'" EXIT
    trap_add "finish_installation" EXIT

    for i in "${!install_compiler_software_support_list[@]}"; do
        if [ "${install_compiler_options[i]}" == "[v]" ]; then
            eval "${install_compiler_software_support_list[i]}_install"
        fi
    done
    if [ "${install_compiler_options[0]}" == "[v]" ]; then
        Bisheng_Compiled_Version_install
    fi
    if [ "${install_compiler_options[1]}" == "[v]" ]; then
        GCC_Compiled_Version_install
    fi

    if [ "${install_hio_options[0]}" = "[v]" ]; then
        component_hio_install
    fi
}

Bisheng_Compiled_Version_install() {
    user_choose "install_bisheng"
    for i in "${!install_bisheng_software_support_list[@]}"; do
        if [ "${install_bisheng_options[i]}" == "[v]" ]; then
            eval "${install_bisheng_software_support_list[i]}_install bisheng"
        elif [[ "${install_bisheng_software_support_list[i]}" == "KULITHO" && $one_click -eq 1 && "$install_kulitho" == "y" ]]; then
            eval "${install_bisheng_software_support_list[i]}_install bisheng"
        fi
    done
}

GCC_Compiled_Version_install() {
    user_choose "install_gcc"
    for i in "${!install_gcc_software_support_list[@]}"; do
        if [ "${install_gcc_options[i]}" == "[v]" ]; then
            eval "${install_gcc_software_support_list[i]}_install gcc"
        elif [[ "${install_gcc_software_support_list[i]}" == "KULITHO" && $one_click -eq 1 && "$install_kulitho" == "y" ]]; then
            eval "${install_gcc_software_support_list[i]}_install gcc"
        fi
    done
}

component_hio_install() {
    user_choose "install_hio"
    for i in "${!install_hio_software_support_list[@]}"; do
        if [ "${install_hio_options[i]}" == "[v]" ]; then
            eval "${install_hio_software_support_list[i]}_install"
        fi
    done
}

_script_name="install.sh"
show_help() {
    echo "Usage: sh ${_script_name}" '[-y] [--prefix=]'
    echo "  -y                   Install HPCKit with default options, should be used with --prefix."
    echo '  --prefix=            Set HPCKit install path, should be used with -y.'
    echo '  --hmpi_type=         Set HMPI type.--hmpi_type=[rdma(default)|mlnx]'
    echo '  --install_kulitho=   Set whether install KuLitho.--install_kulitho=[n(default)|y]'
    echo '  --kulitho_path=      Set KuLitho package path(default:'$current_dir'/package), should be used when --install_kulitho=y'
    echo "  -h                   Show usage."
    echo ''
}

check_hmpi_type() {
    local net_type=$1
    if [[ "$net_type" != "rdma" && "$net_type" != "mlnx" ]]; then
        logError "'$net_type' has an invalid value."
        exit 1
    fi
}

one_click=0
hmpi_type="rdma"
parse_args() {
    while [ "$#" -gt 0 ]; do
        case "$1" in
        -h)
            show_help
            exit 0
            ;;
        -y)
            one_click=1
            set_render_use_default 1
            shift
            ;;
        --prefix=*)
            selected_install_path="${1#*=}"
            shift
            ;;
        --hmpi_type=*)
            hmpi_type="${1#*=}"
            check_hmpi_type ${hmpi_type}
            shift
            ;;
        --install_kulitho=*)
            install_kulitho="${1#*=}"
            shift
            ;;
        --kulitho_path=*)
            if [[ $install_kulitho != "y" ]]; then
                logError "parameter error: --kulitho_path should be used when --install_kulitho=y!"
                show_help
                exit 1
            fi
            kulitho_package_path="${1#*=}"
            shift
            ;;
        *)
            echo "Unknown option: $1"
            echo ""
            show_help
            exit 0
            ;;
        esac
    done
    [[ $one_click -eq 1 ]]; TESTA=$?
    [[ $selected_install_path != "" ]]; TESTB=$?
    if [[ $TESTA -ne $TESTB ]]; then
        show_help
        exit 1
    fi

    install_selected_software
}


parse_args $@